package cn.com.mdx.sort.practice.collinearpoints;

import edu.princeton.cs.algs4.StdDraw;

import java.util.Comparator;

/**
 * <p>
 *
 * @author ：huangy
 * @date ：Created in 2020/9/16 11:28 上午
 */
public class Point implements Comparable<Point> {

    /**
     * x坐标
     */
    private int x;
    /**
     * y坐标
     */
    private int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    /**
     * @return void
     * @Author huangy
     * @description //TODO 画点
     * @date 5:41 下午 2020/9/16
     **/
    public void draw() {
        StdDraw.point(x, y);
    }

    /**
     * @param that 给定点
     * @return void
     * @Author huangy
     * @description //TODO 从此点绘制线段到给定点
     * @date 5:41 下午 2020/9/16
     **/
    public void drawTo(Point that) {
        StdDraw.line(this.x, this.y, that.x, that.y);
    }

    /**
     * @return java.lang.String
     * @Author huangy
     * @description //TODO 字符串
     * @date 5:44 下午 2020/9/16
     **/
    public String toString() {
        return "point(" + x + ", " + y + ")";
    }

    /**
     * <p> 通过y坐标比较两个点，通过x坐标断开关系
     *
     * @param that 给定点
     * @return int
     * @Author huangy
     * @description //TODO
     * @date 5:44 下午 2020/9/16
     **/
    public int compareTo(Point that) {
        //检测点是否合法
        checkPoint(that);
        if (this.x == that.x && this.y == that.y) return 0;
        //当且仅当y0 < y1或y0 = y1并且x0 < x1时, 点(x0,y0)小于点(x1,y1)
        else if (this.y < that.y || (this.y == that.y && this.x < that.x)) return -1;
        return 1;
    }

    /**
     * <p> 计算此点和给定点的斜率
     *
     * @param that 给定点
     * @return double
     * @Author huangy
     * @description //TODO
     * @date 5:47 下午 2020/9/16
     **/
    public double slopeTo(Point that) {
        //检测此点坐标是否合法
        checkPoint(this);
        //检测点是否合法
        checkPoint(that);
        //如果两个点重合，则斜率是负无穷大
        if (this.x == that.x && this.y == that.y) return Double.NEGATIVE_INFINITY;
            //如果两个点x坐标相同，则斜率为正无穷大
        else if (this.x == that.x) return Double.POSITIVE_INFINITY;
        return (double) (that.y - this.y) / (that.x - this.x);
    }

    /**
     * @return java.util.Comparator<cn.com.mdx.sort.practice.collinearpoints.Point>
     * @Author huangy
     * @description //TODO 比较给定两点到此点的斜率
     * @date 5:48 下午 2020/9/16
     **/
    public Comparator<Point> slopeOrder() {
        return new SlopeOrderComparator();
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    /**
     * @Author huangy
     * @description //TODO 斜率比较器
     * @date 3:03 下午 2020/9/17
     * @return
     **/
    private class SlopeOrderComparator implements Comparator<Point> {
        @Override
        public int compare(Point pointA, Point pointB) {
            //点A与此点的斜率
            double slopeA = slopeTo(pointA);
            //点B与此点的斜率
            double slopeB = slopeTo(pointB);
            if (slopeA == slopeB) return 0;
            else if (slopeA < slopeB) return -1;
            return 1;
        }
    }

    /**
     * @param point 给定点
     * @return void
     * @Author huangy
     * @description //TODO
     * @date 5:54 下午 2020/9/16
     **/
    private void checkPoint(Point point) {
        if (point.x < 0 || point.x > 32767) throw new IllegalArgumentException("给定点的x坐标超出了指定范围0~32767");
        if (point.y < 0 || point.y > 32767) throw new IllegalArgumentException("给定点的y坐标超出了指定范围0~32767");
    }
}
